#include "stdafx.h"
#include "kernel.h"
#include "proc.h"
#include "view.h"

namespace xm
{
	vxvma_t process_t::gst_ldr_insert_module( mlinf_t& mli )
	{
		return (opts & PROC_64Bit) ? 
			gst_ldr_insert_module64(mli) : 
			gst_ldr_insert_module32(mli);
	}
	vxvma_t process_t::gst_ldr_insert_module32( mlinf_t& mli )
	{
		optr<image_view_t> vo = modmgr.find_prev_module( mli.LoadBase );
		//////////////////////////////////////////////////////////////////////////
		vxvma_t order_prev = vo ? vo->mi.ldr_mod_addr : 0;
		//////////////////////////////////////////////////////////////////////////
		size_t len_full = wcslen( mli.wFullName);
		size_t len_short = wcslen( mli.wDllName);
		size_t full_bytes = (len_full+1)*sizeof(WCHAR);
		size_t short_bytes = (len_short+1)*sizeof(WCHAR);
		size_t want = sizeof(LDR_MODULE32) + full_bytes + short_bytes;
		ghptr gbuf(this);
		if( !gbuf.alloc( want ) ) return NULL;
		LDR_MODULE32 gst_snap = {};
		gst_snap.BaseAddress = mli.LoadBase;
		gst_snap.EntryPoint = mli.EntryPoint;
		gst_snap.SizeOfImage = mli.SizeOfImage;
		gst_snap.LoadCount = mli.LoadCount;
		gst_snap.TlsIndex = mli.TlsIndex;
		gst_snap.CheckSum = mli.CheckSum;
		gst_snap.TimeDateStamp = mli.TimeDateStamp;
		gst_snap.Flags = mli.Flags;
		gst_snap.FullDllName.Buffer = gbuf.ptr + sizeof(LDR_MODULE32);
		gst_snap.FullDllName.Length = len_full;
		gst_snap.FullDllName.MaximumLength = len_full + 1;
		gst_snap.BaseDllName.Buffer = gbuf.ptr + sizeof(LDR_MODULE32) + full_bytes;
		gst_snap.BaseDllName.Length = len_short;
		gst_snap.BaseDllName.MaximumLength = len_short + 1;
		if( !gbuf.write( 0, &gst_snap, sizeof(gst_snap) ) )
			return NULL;
		if( !gbuf.write( sizeof(gst_snap), mli.wFullName, full_bytes ) )
			return NULL;
		if( !gbuf.write( sizeof(gst_snap) + full_bytes, mli.wDllName, short_bytes ) )
			return NULL;
		//////////////////////////////////////////////////////////////////////////
		// call guset.insert_module
		RFAILED_( ldr_insert( peb, gbuf.ptr, order_prev ), NULL );
		//////////////////////////////////////////////////////////////////////////
		return gbuf.detach();
	}
	vxvma_t process_t::gst_ldr_insert_module64( mlinf_t& mli  )
	{
		size_t len_full = wcslen( mli.wFullName);
		size_t len_short = wcslen( mli.wDllName);
		size_t full_bytes = (len_full+1)*sizeof(WCHAR);
		size_t short_bytes = (len_short+1)*sizeof(WCHAR);
		size_t want = sizeof(LDR_MODULE32) + full_bytes + short_bytes;
		ghptr gbuf(this);
		if( !gbuf.alloc( want ) ) return NULL;
		LDR_MODULE64 gst_snap = {};
		gst_snap.BaseAddress = mli.LoadBase;
		gst_snap.EntryPoint = mli.EntryPoint;
		gst_snap.SizeOfImage = mli.SizeOfImage;
		gst_snap.LoadCount = mli.LoadCount;
		gst_snap.TlsIndex = mli.TlsIndex;
		gst_snap.CheckSum = mli.CheckSum;
		gst_snap.TimeDateStamp = mli.TimeDateStamp;
		gst_snap.Flags = mli.Flags;
		gst_snap.FullDllName.Buffer = gbuf.ptr + sizeof(LDR_MODULE64);
		gst_snap.FullDllName.Length = len_full;
		gst_snap.FullDllName.MaximumLength = len_full + 1;
		gst_snap.BaseDllName.Buffer = gbuf.ptr + sizeof(LDR_MODULE64) + full_bytes;
		gst_snap.BaseDllName.Length = len_short;
		gst_snap.BaseDllName.MaximumLength = len_short + 1;
		if( !gbuf.write( 0, &gst_snap, sizeof(gst_snap) ) )
			return NULL;
		if( !gbuf.write( sizeof(gst_snap), mli.wFullName, full_bytes ) )
			return NULL;
		if( !gbuf.write( sizeof(gst_snap) + full_bytes, mli.wDllName, short_bytes ) )
			return NULL;
		//////////////////////////////////////////////////////////////////////////
		// call guset.insert_module

		//////////////////////////////////////////////////////////////////////////
		return gbuf.detach();
	}
	vxvma_t process_t::gst_ldr_remove_module( vxvma_t modp )
	{
		return 0;
	}

	vxvma_t	process_t::gst_rtl_fill_unicode( vxvma_t gst_unicode_ptr, LPCWSTR wstr )
	{
		size_t len = wcslen( wstr );
		size_t wbytes = (len+1)*sizeof(WCHAR);
		//////////////////////////////////////////////////////////////////////////
		ghptr gbuf(this);
		if( !gbuf.alloc( wbytes ) ) return NULL;
		if(opts&PROC_64Bit)
		{
			UNICODE_STRING64 us64 = {};
			us64.Length = len;
			us64.MaximumLength = len + 1;
			us64.Buffer = gbuf.ptr;
			if( !gbuf.abwrite( gst_unicode_ptr, &us64, sizeof(us64) ) )
				return NULL;
			if( !gbuf.write( 0, wstr, wbytes ) )
				return NULL;
		}
		else 
		{
			UNICODE_STRING32 us32 = {};
			us32.Length = len;
			us32.MaximumLength = len + 1;
			us32.Buffer = gbuf.ptr;
			if( !gbuf.abwrite( gst_unicode_ptr, &us32, sizeof(us32) ) )
				return NULL;
			if( !gbuf.write( 0, wstr, wbytes ) )
				return NULL;
		}
		return gbuf.detach();
	}

	vxvma_t process_t::gst_rtl_alloc_unicode_string( LPCWSTR wstr )
	{
		size_t len = wcslen( wstr );
		size_t wbytes = (len+1)*sizeof(WCHAR);
		size_t want = (opts&PROC_64Bit)?sizeof(UNICODE_STRING64):sizeof(UNICODE_STRING32);
		want += wbytes;
		
		ghptr gbuf(this);
		if( !gbuf.alloc( want ) ) return NULL;

		if(opts&PROC_64Bit)
		{
			UNICODE_STRING64 us64 = {};
			us64.Length = len;
			us64.MaximumLength = len + 1;
			us64.Buffer = gbuf.ptr;
			if( !gbuf.write( 0, &us64, sizeof(us64) ) )
				return NULL;
			if( !gbuf.write( sizeof(us64), wstr, wbytes ) )
			return NULL;
		}
		else 
		{
			UNICODE_STRING32 us32 = {};
			us32.Length = len;
			us32.MaximumLength = len + 1;
			us32.Buffer = gbuf.ptr;
			if( !gbuf.write( 0, &us32, sizeof(us32) ) )
				return NULL;
			if( !gbuf.write( sizeof(us32), wstr, wbytes ) )
				return NULL;
		}

		return gbuf.detach();
	}


};